package com.cxx.home.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cxx.home.dto.travel.TravelRecordDto;
import com.cxx.home.dto.travel.TravelSpotDto;
import com.cxx.home.dto.travel.TravelStatsDto;
import com.cxx.home.dto.travel.TravelSummaryDto;
import com.cxx.framework.web.CustomException;
import com.cxx.home.dao.TravelDao;
import com.cxx.home.entity.TravelImage;
import com.cxx.home.entity.TravelRecord;
import com.cxx.home.entity.TravelSpot;
import com.cxx.home.entity.TravelVideo;
import com.cxx.home.mapper.TravelImageMapper;
import com.cxx.home.mapper.TravelRecordMapper;
import com.cxx.home.mapper.TravelSpotMapper;
import com.cxx.home.mapper.TravelVideoMapper;
import com.cxx.home.service.TravelService;
import com.cxx.home.vo.TravelQueryVo;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class TravelServiceImpl implements TravelService {
    @Resource
    private TravelDao travelDao;

    @Resource
    private TravelSpotMapper travelSpotMapper;

    @Resource
    private TravelRecordMapper travelRecordMapper;

    @Resource
    private TravelImageMapper travelImageMapper;

    @Resource
    private TravelVideoMapper travelVideoMapper;

    @Override
    @Transactional
    public Boolean addTravelSpot(TravelSpotDto travelSpotDto) {
        LambdaQueryWrapper<TravelSpot> queryWrapper = new LambdaQueryWrapper<>();
        if (travelSpotMapper.exists(queryWrapper.eq(TravelSpot::getName, travelSpotDto.getName()))) {
            throw new CustomException("该景点已经存在");
        }

        TravelSpot travelSpot = new TravelSpot();
        BeanUtils.copyProperties(travelSpotDto, travelSpot);
        travelSpot.setCity(travelSpotDto.getArea().get(1));
        travelSpotMapper.insert(travelSpot);

        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean updateTravelSpot(Long id, TravelSpotDto travelSpotDto) {
        if (travelSpotMapper.selectById(id) == null) {
            throw new CustomException("该景点不存在");
        }

        TravelSpot travelSpot = new TravelSpot();
        BeanUtils.copyProperties(travelSpotDto, travelSpot);
        travelSpot.setId(id);
        travelSpot.setCity(travelSpotDto.getArea().get(1));
        travelSpotMapper.updateById(travelSpot);

        return Boolean.TRUE;
    }

    @Override
    @Transactional
    public Boolean deleteTravelSpot(Long id) {
        travelSpotMapper.deleteById(id);
        travelRecordMapper.delete(Wrappers.lambdaQuery(TravelRecord.class).eq(TravelRecord::getTravelId, id));

        return Boolean.TRUE;
    }

    @Override
    public Boolean addTravelRecord(TravelRecordDto travelRecordDto) {
        LambdaQueryWrapper<TravelSpot> queryWrapper = new LambdaQueryWrapper<>();
        TravelSpot travelSpot = travelSpotMapper.selectOne(queryWrapper.eq(TravelSpot::getName, travelRecordDto.getName()));
        if (travelSpot == null) {
            throw new CustomException("该景点不存在");
        }

        TravelRecord travelRecord = new TravelRecord();
        travelRecord.setTravelId(travelSpot.getId());
        BeanUtils.copyProperties(travelRecordDto, travelRecord);
        travelRecordMapper.insert(travelRecord);

        insertTravelImage(travelRecord.getTravelId(), travelRecordDto.getImageList());
        insertTravelVideo(travelRecord.getTravelId(), travelRecordDto.getVideoList());
        return Boolean.TRUE;
    }

    @Override
    public Boolean updateTravelRecord(Long id, TravelRecordDto travelRecordDto) {
        if (travelRecordMapper.selectById(id) == null) {
            throw new CustomException("该记录不存在");
        }

        TravelRecord travelRecord = new TravelRecord();
        BeanUtils.copyProperties(travelRecordDto, travelRecord);
        travelRecord.setId(id);
        travelRecordMapper.updateById(travelRecord);

        deleteTravelImage(id);
        deleteTravelVideo(id);

        insertTravelImage(id, travelRecordDto.getImageList());
        insertTravelVideo(id, travelRecordDto.getVideoList());
        return Boolean.TRUE;
    }

    @Override
    public Boolean deleteTravelRecord(Long id) {
        travelRecordMapper.deleteById(id);

        return Boolean.TRUE;
    }

    private void insertTravelImage(Long travelId, List<String> imageList) {
        if (!imageList.isEmpty()) {
            travelDao.insertTravelImage(travelId, imageList);
        }
    }

    private void insertTravelVideo(Long travelId, List<String> videoList) {
        if (!videoList.isEmpty()) {
            travelDao.insertTravelVideo(travelId, videoList);
        }
    }

    private void deleteTravelImage(Long id) {
        travelImageMapper.delete(Wrappers.lambdaQuery(TravelImage.class).eq(TravelImage::getRecordId, id));
    }

    private void deleteTravelVideo(Long id) {
        travelVideoMapper.delete(Wrappers.lambdaQuery(TravelVideo.class).eq(TravelVideo::getRecordId, id));
    }

    @Override
    public TravelSpotDto queryTravelSpot(Long id) {
        if (travelSpotMapper.selectById(id) == null) {
            throw new CustomException("该景点不存在");
        }

        return travelDao.queryTravelSpot(id);
    }

    @Override
    public IPage<TravelSummaryDto> queryTravelSummary(Integer currentPage, Integer pageSize, TravelQueryVo travelQueryVo) {
        // 这里只能先对主表进行分页 然后在查询子表信息
        // 不能使用Left Join关联表查询，因为这里是一对多数据，关联查询会导致数据有重复
        // 从而导致page计算错误（会把重复的数据当成多条记录，实际上只有1条记录）
        IPage<TravelSummaryDto> travelSummaryPage = travelDao.queryTravelSummary(new Page<>(currentPage, pageSize), travelQueryVo);
        List<TravelSummaryDto> travelSummaryList = travelSummaryPage.getRecords();
        for (TravelSummaryDto travelSummary : travelSummaryList) {
            travelSummary.setRecordList(travelDao.queryTravelRecordById(travelSummary.getId()));
        }

        travelSummaryPage.setRecords(travelSummaryList);
        return travelSummaryPage;
    }

    @Override
    public List<TravelRecordDto> queryTravelRecord(String startDate, String endDate) {
        return travelDao.queryTravelRecord(startDate, endDate);
    }

    @Override
    public List<String> queryTravelSpotName() {
        return travelSpotMapper.selectList(null)
                .stream().map(TravelSpot::getName).collect(Collectors.toList());
    }

    @Override
    public List<String> queryTravelCategory() {
        return travelDao.queryTravelCategory();
    }

    @Override
    public TravelStatsDto queryTravelStats() {
        return travelDao.queryTravelStats();
    }
}
